import gtk

from Bases import BaseObject, Scaler
from Bases import Color as ColorObj

class Color(BaseObject):
    color_keys = {'red':'red_float', 'green':'green_float', 'blue':'blue_float'}
    hsv_keys = ['hue', 'sat', 'val']
    def __init__(self, **kwargs):
        self._attribute = None
        super(Color, self).__init__(**kwargs)
        self.widget_set_by_program = False
        self.register_signal('color_changed')
        self.scale_factor = float(kwargs.get('scale_factor', 255))
        self.color = ColorObj()
        self.setup_widgets(**kwargs)
        self.attribute = kwargs.get('attribute')
        #self.on_attribute_value_changed()
        #self.attribute.connect('value_changed', self.on_attribute_value_changed)
        
    @property
    def attribute(self):
        return self._attribute
    @attribute.setter
    def attribute(self, value):
        if self.attribute:
            self.attribute.disconnect(callback=self.on_attribute_value_changed)
        self._attribute = value
        if self.attribute:
            self.on_attribute_value_changed()
            self.attribute.connect('value_changed', self.on_attribute_value_changed)
        
    def unlink(self):
        super(Color, self).unlink()
        self.attribute = None
        
    def on_widget_update(self, *args):
        if not self.widget_set_by_program:
            hsv = self.get_widget_color()
            self.color.hsv = dict(zip(self.hsv_keys, hsv))
            if self.attribute:
                self.attribute.set_hsv(**self.color.hsv)
            self.emit('color_changed', color=self.color, obj=self)
        self.widget_set_by_program = False
        
    def update_widget_color(self, **kwargs):
        self.color.hsv = kwargs
        hsv = self.color.hsv_seq
        #print self.color.hsv
        if hsv != self.get_widget_color():
            self.widget_set_by_program = True
            self.set_widget_color(hsv)
            self.widget_set_by_program = False
        
    def on_attribute_value_changed(self, **kwargs):
        self.update_widget_color(**self.attribute.hsv)
    
class EntryBuffer(BaseObject):
    def __init__(self, **kwargs):
        super(EntryBuffer, self).__init__(**kwargs)
        self.register_signal('modified')
        self.src_object = kwargs.get('src_object')
        self.src_attr = kwargs.get('src_attr')
        self.src_signal = kwargs.get('src_signal')
        self.setup_widgets(**kwargs)
        if self.src_signal:
            self.src_object.bind(**{self.src_signal:self.on_object_value_changed})
        self.widget_set_by_program = True
        self.set_widget_text(self.get_object_text())
    def unlink(self):
        if self.src_signal:
            self.src_object.unbind(self.on_object_value_changed)
    def get_widget_text(self):
        pass
    def set_widget_text(self, text):
        pass
    def set_object_text(self, text):
        setattr(self.src_object, self.src_attr, text)
    def get_object_text(self):
        return getattr(self.src_object, self.src_attr)
    def on_widget_value_changed(self, *args, **kwargs):
        self.widget_set_by_program = True
        self.set_object_text(self.get_widget_text())
    def on_object_value_changed(self, *args, **kwargs):
        if not self.widget_set_by_program:
            self.set_widget_text(self.get_object_text())
        self.widget_set_by_program = False

class Spin(BaseObject):
    def __init__(self, **kwargs):
        super(Spin, self).__init__(**kwargs)
        self.value_type = None
        self.src_object = kwargs.get('src_object')
        self.src_attr = kwargs.get('src_attr')
        self.src_Property = kwargs.get('Property')
        self.scale_factor = kwargs.get('scale_factor', 1)
        if self.src_Property:
            self.src_attr = self.src_Property
            self.src_object.bind(**{self.src_Property:self.on_object_value_changed})
            self.value_type = self.src_object.Properties[self.src_Property].type
        self.widget_value_set_by_program = False
        self.object_value_set_by_program = False
        kwargs.setdefault('value', 0)
        kwargs.setdefault('value_min', 0)
        kwargs.setdefault('value_max', 255)
        self.setup_widgets(**kwargs)
    def unlink(self):
        if self.src_object:
            self.src_object.unbind(self.on_object_value_changed)
        super(Spin, self).unlink()
    def on_object_value_changed(self, *args, **kwargs):
        #if not self.object_value_set_by_program:
        #value = getattr(self.src_object, self.src_attr)
        self.set_widget_value(self.get_object_value())
        #self.object_value_set_by_program = False
    def get_object_value(self):
        return getattr(self.src_object, self.src_attr) * self.scale_factor
    def set_object_value(self, value):
        #self.object_value_set_by_program = True
        if self.value_type is not None:
            value = self.value_type(value)
        setattr(self.src_object, self.src_attr, value / self.scale_factor)

class Radio(BaseObject):
    def __init__(self, **kwargs):
        super(Radio, self).__init__(**kwargs)
        self.widget_signals = []
        self.attribute = kwargs.get('attribute')
        self.attribute.connect('value_changed', self.on_attribute_parameter_changed)
        self.widgets = {}
        self.widget_signals = {}
        self.setup_widgets()
        
    def setup_widgets(self):
        pass
        
    def unlink(self):
        self.attribute.disconnect(callback=self.on_attribute_value_changed)
        for key, val in self.widget_signals.iteritems():
            self.widgets[key].disconnect(val)
            
    def on_attribute_parameter_changed(self, **kwargs):
        key = kwargs.get('name')
        self.widgets[key].set_active(True)
            
    def on_widgets_clicked(self, widget):
        for key, val in self.widgets.iteritems():
            if val.get_active():
                self.attribute.set_parameter(key)

class Toggle(BaseObject):
    def __init__(self, **kwargs):
        super(Toggle, self).__init__(**kwargs)
        self.widget_signals = []
        self.src_object = kwargs.get('src_object')
        self.src_attr = kwargs.get('src_attr')
        self.toggled_by_program = False
        self.setup_widgets(**kwargs)
        #self.set_widget_state(getattr(self.src_object, self.src_attr))
        self.on_object_value_changed()
        
    def setup_widgets(self, **kwargs):
        pass
        
    def get_widget_state(self):
        pass
        
    def set_widget_state(self, state):
        pass
        
    def unlink(self):
        pass
            
    def on_object_value_changed(self, *args, **kwargs):
        state = getattr(self.src_object, self.src_attr)
        if state != self.get_widget_state():
            self.toggled_by_program = True
            self.set_widget_state(state)
            
    def on_widget_toggled(self, *args):
        if not self.toggled_by_program:
            setattr(self.src_object, self.src_attr, not getattr(self.src_object, self.src_attr))
        self.toggled_by_program = False

class Fader(BaseObject):
    def __init__(self, **kwargs):
        self._attribute = None
        super(Fader, self).__init__(**kwargs)
        self.register_signal('obj_value_changed')
        self.fader_drag = False
        self.widget_signals = []
        self.value_range = [0, 255]
        self.offset_value_range = kwargs.get('offset_value_range', False)
        self.value_symbol = ''
        self.setup_widgets(**kwargs)
        self.attribute = kwargs.get('attribute')
        
        #if self.attribute.value is not None:
        #    self.set_widget_value(self.attribute.value)
        
        #self.attribute.connect('value_changed', self.on_attribute_value_changed)
        
    @property
    def attribute(self):
        return self._attribute
    @attribute.setter
    def attribute(self, value):
        if self.attribute:
            self.attribute.disconnect(callback=self.on_attribute_value_changed)
            self.value_symbol = ''
        self._attribute = value
        if self.attribute:
            #if self.attribute.value is not None:
            if self.offset_value_range:
                self.value_range = [0, self.attribute.value_max - self.attribute.value_min]
            else:
                self.value_range = [self.attribute.value_min, self.attribute.value_max]
            self.value_symbol = getattr(self.attribute, 'value_symbol', '')
            self.set_widget_range()
            self.set_widget_value(self.attribute.value)
            self.attribute.connect('value_changed', self.on_attribute_value_changed)
                
    def setup_widgets(self, **kwargs):
        pass
        
    def unlink(self):
        #self.attribute.disconnect(callback=self.on_attribute_value_changed)
        self.attribute = None
        for id in self.widget_signals:
            self.widget.disconnect(id)
            
    def on_widget_button_press(self, *args):
        self.fader_drag = True
    def on_widget_button_release(self, *args):
        self.fader_drag = False
    
    def on_widget_change_value(self, *args):
        if self.attribute:
            self.attribute.value = self.get_widget_value()
    
    def on_attribute_value_changed(self, **kwargs):
        value = self.attribute.value
        if self.fader_drag is False:
            self.set_widget_value(value)
            #print 'fader %s, attribute %s, value %s' % (self, attrib, value)
            self.emit('obj_value_changed', attribute=self.attribute, obj=self)
        
    def set_widget_value(self, value):
        pass
    def get_widget_value(self):
        pass
    def set_widget_range(self):
        pass
    def set_widget_label(self, label):
        pass
        
class ScaledFader(BaseObject):
    def __init__(self, **kwargs):
        super(ScaledFader, self).__init__(**kwargs)
        
        self.register_signal('obj_value_changed')
        self.parameter = kwargs.get('parameter')
        
        uilog = False
        if self.parameter.units == 'dB':
            uilog = True
        self.ui_scale = {'min':self.parameter.scaled_min, 'max':self.parameter.scaled_max, 'LOG':uilog}
        self.param_scale = {'min':self.parameter.value_min, 'max':self.parameter.value_max}
        
        self.scaler = Scaler(scales={'ui':self.ui_scale, 'param':self.param_scale})
        
        self.fader_drag = False
        if self.parameter.value is not None:
            self.scaler.set_value('param', self.parameter.value)
        self.widget_signals = []
        self.setup_widgets(**kwargs)
        self.parameter.connect('value_update', self.on_parameter_value_update)
        self.scaler.connect('value_update', self.on_scaler_value_update)
    
    def setup_widgets(self, **kwargs):
        pass
        
    def unlink(self):
        self.parameter.disconnect(callback=self.on_parameter_value_update)
        for id in self.widget_signals:
            self.widget.disconnect(id)
            
    def on_widget_button_press(self, *args):
        self.fader_drag = True
    def on_widget_button_release(self, *args):
        self.fader_drag = False
    
    def on_widget_change_value(self, range, scroll, value):
        pass
    
    def on_parameter_value_update(self, **kwargs):
        param = kwargs.get('parameter')
        value = kwargs.get('value')
        if param == self.parameter and self.fader_drag is False:
            #print 'fader:', kwargs
            #self.adj.set_value(value)
            self.scaler.set_value('param', value)
        
    def set_widget_value(self, value):
        pass
        
    def on_scaler_value_update(self, **kwargs):
        name = kwargs.get('name')
        value = kwargs.get('value')
        if name == 'ui':
            self.set_widget_value(value)
        elif name == 'param':
            if int(value) != self.parameter.value:
                self.parameter.set_value(int(value))
                self.emit('obj_value_changed', parameter=self.parameter, obj=self)#, adj=self.adj)
                #print 'param: ', value
        #print 'adj: ', self.adj.get_value(), ', param: ', self.parameter.value

class Meter(BaseObject):
    def __init__(self, **kwargs):
        super(Meter, self).__init__(**kwargs)
        
